local japi = require 'jass.japi'
local handle_manager = handle_manager_class:create()
local flagcov = require 'util.flag'

local message = {}
setmetatable(message, message)
ac.message = message

message.alltriggers = {}
message.allacts = setmetatable({}, {__mode = 'kv'})

message.__index = require 'jass.message'
message.keyboard = {}
for k,v in pairs(message.__index.keyboard) do 
    message.keyboard[k] = v 
    message.keyboard[v] = k 
end 

-- 标志辅助
message.flags = {
    ['队列'] = 1 << 0,
    ['瞬发'] = 1 << 1,
    ['独立'] = 1 << 2,
    ['群体'] = 1 << 3,
    ['阵型'] = 1 << 4,
    ['恢复'] = 1 << 5,
    ['交互'] = 1 << 6,
}

-- 客户端在线
function message:is_client_online()
    return self.client_online == true
end 

-- 客户端查看录像
function message:is_client_replay()
    return self.client_replay == true 
end 

-- 客户端观战
function message:is_client_observer()
    return self.client_observer == true
end 


---全局事件回调
---@param name string 事件名称
---@param ... any 参数
function message.notify(name, ...)
    local trigger = message.alltriggers[name]
    if not trigger then return true end
    local bool = true 
    for i = #trigger.actors, 1, -1 do 
        local act = trigger.actors[i]
        if act:execute(...) == false then 
            bool = false
            break
        end
    end
    return bool
end

---全局事件监听
---@param name string
function message:register(name)
    local trigger = message.alltriggers[name]
    if not trigger then
        trigger = ac.trigger.create(name)
        trigger.remove = function(t)
            for i = #trigger.actors, 1, -1 do 
                local act = trigger.actors[i]
                act:remove()
                message.allacts[act] = nil
            end 
            message.alltriggers[name] = nil
        end
        message.alltriggers[name] = trigger
    end 
    return function (func)
        local act = trigger:add_actor(func)
        act.key = "消息事件>" .. name
        message.allacts[act] = true
        return act
    end
end

message.on     = message.register
message.event  = message.register


--- 消息事件解析列表
local event_map = {

    key_down = function (msg)
        --[键码,组合键状态 alt = 4, ctrl = 2,]
        return message.notify("键盘按下", msg.code, msg.state )
    end,

    key_up = function (msg)
        return message.notify("键盘弹起", msg.code, msg.state )
    end,
 
    mouse_ability = function (msg)
        return message.notify("点击技能按钮", msg.ability, msg.order )
    end,

    mouse_item = function (msg)
        return message.notify("点击物品按钮", msg.ability, msg.order ,msg.code)
    end,

    -- mouse_down = function (msg)
    --     return message.notify("鼠标按下", japi.GetMouseX(), japi.GetMouseY(), msg.code)
    -- end,

    -- mouse_up = function (msg)
    --     return message.notify("鼠标弹起", japi.GetMouseX(), japi.GetMouseY())
    -- end,

    select_unit = function (msg)
        return message.notify("选择单位", msg.unit)
    end,
}

message._last_msg_info = nil 

---改建
function message:change_code(code)
    local msg = message._last_msg_info
    if msg and msg.type:find("key_") and type(code) == 'number' and message.keyboard[code] then
        msg.code = code
        return true
    end
    return false
end 

---消息hook
function message.__index.hook(msg)
    local name = msg.type
    local func = event_map[name]
    if func then 
        message._last_msg_info = msg
        local bool = func(msg)
        message._last_msg_info = nil
        return bool
    end 
    return true
end

local order_event_map = {

    order_immediate = function(msg)
        local orderid, _, flag = table.unpack(msg, 2)
        local unit, order, flags = message.selection(), Order[orderid], flagcov.tostring(flag, message.flags)
        if message.notify("本地命令", "无目标命令", unit, order, flags) == false then
            return false
        end 
        return message.notify("无目标命令",unit, order, flags)
    end,

    order_point = function(msg)
        local orderid, _, x, y, flag = table.unpack(msg, 2)
        local unit, order, flags, x, y = message.selection(), Order[orderid], flagcov.tostring(flag, message.flags), x, y
        if message.notify("本地命令", "点目标命令", unit, order, flags, x, y) == false then
            return false
        end 
        return message.notify("点目标命令", unit, order, flags, x, y)
    end,

    order_target = function(msg)
        local orderid, _, x, y, widget, flag = table.unpack(msg, 2)
        local unit, order, flags, widget = message.selection(), Order[orderid], flagcov.tostring(flag, message.flags), widget
        if message.notify("本地命令", "指定目标命令", unit, order, flags, widget, x, y) == false then
            return false
        end 
        return message.notify("指定目标命令", unit, order, flags, widget, x, y )
    end,

    order_smart = function(msg)
        local widget, flag = table.unpack(msg, 4)
        local unit, order, flags, widget = message.selection(), "smart", flagcov.tostring(flag, message.flags), widget
        if message.notify("本地命令", "右键命令", unit, order, flags, widget) == false then
            return false
        end 
        return message.notify("右键命令", unit, order, flags, widget )
    end,

    order_discard = function(msg)
        local x, y, widget, item, flag = table.unpack(msg, 4)
        local unit, order, flags = message.selection(), "dropitem", flagcov.tostring(flag, message.flags)
        if message.notify("本地命令", "丢弃物品", unit, order, flags, item, widget, x, y) == false then
            return false
        end 
        return message.notify("丢弃物品", unit, order, flags, item, widget, x, y)
    end,
}

-- 发送message消息
function message:order_call(_order_info)
    return self.__index[_order_info[1]](table.unpack(_order_info, 2)) 
end

---获取最后的ordermsg
function message:get_order_info()
    return self._order_info
end 

---命令hook
function message.__index.order_hook(msg)
    local name = msg[1]
    local func = order_event_map[name]
    if func then 
        message._order_info = msg
        return func(msg)
    end 
    return true
end

function message.convert_flag(flags)
    return flagcov.tobit(flags or "", message.flags)
end 

local function init()
    local list = message.load_window_infos()
    message.client_online = true
    for index, info in ipairs(list) do
        local title = info.title or ''
        if title:find('直播') then
            message.client_online = false
            message.client_observer = true
        elseif title:find('录像') then
            message.client_online = false
            message.client_replay = true
        end
    end
    return 0
end

init()

--[[
    1 << 0 1 队列指令 按住shift发布指令  
    1 << 1 2 瞬发指令 瞬发不打断 研发科技 购买物品 移动物品 等等 该指令将会无视队列 优先发布
    1 << 2 4 独立指令 选中多个单位时只对首选单位有效
    1 << 3 8 群体指令 选中的单位全部发布这个指令
    1 << 4 16 阵型指令 只有 群体指令 才能使用保持队形发布指令 而且必须是 能让单位移动的命令才可以 无目标指令 和 部分瞬发|交互类指令 不适用
    1 << 5 32 恢复指令 发布指令后恢复原来的指令
    1 << 6 64 交互指令 研发科技 购买物品 移动物品 丢弃物品 等等 

    移动物品 是 右键命令 flag为交互|瞬发 加上恢复就可以做出兽族药膏的效果 
    使用物品 flag为独立|交互 发布的话必须要有这俩不然用不了

    -- 使用物品案例
    local msg = {
        "order_immediate", 
        FourCC("使用第1格物品"), 
        jass.UnitItemInSlot(unit,  0),  -- 使用物品这里必须要加上物品的句柄
        flagcov.tobit(("独立|交互|恢复"), message.flags),
    }
    ac.message:order_call(msg)

    -- 丢弃物品案例
    local msg = {
        "order_discard", 
        0xD0021,
        0,
        0,
        0,
        japi.GetTargetObject(),
        jass.UnitItemInSlot(unit,  0), -- 物品
        68,
    }
    ac.message:order_call(msg)

    -- 交换格子
    local msg = {
        "order_smart", 
        852003, 
        0,
        jass.UnitItemInSlot(unit,  0), -- 物品
        flagcov.tobit(("独立|交互|瞬发"), message.flags),
    }
    ac.message:order_call(msg)

    -- 打开魔法书 
    local msg = {
        "order_immediate", 
        0xD0280, 
        0,
        flagcov.tobit(("独立|交互|瞬发"), message.flags),
    }
    ac.message:order_call(msg)

]]

return message
